﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace JoshuaOneEight
{
	/// <summary>
	/// Form used for learning a verse.
	/// </summary>
	public partial class LearnForm : Form
	{
		#region Constructors

		/// <summary>
		/// Default constructor
		/// </summary>
		public LearnForm()
		{
			InitializeComponent();
		}

		#endregion Constructors

		#region LearnForm Members

		/// <summary>
		/// Sets the current verse.
		/// </summary>
		public Verse Verse
		{
			set
			{
				mVerse = value;
				_Bind();
			}
		}

		#endregion LearnForm Members

		#region Private Members

		private LearnWord[] mWords;
		private Verse mVerse;

		/// <summary>
		/// Bind the current verse to the UI.
		/// </summary>
		private void _Bind()
		{
			if( mVerse != null )
			{
				string[] words = mVerse.Text.Split( ' ' );
				mWords = new LearnWord[words.Length];
				for( int i = 0; i < words.Length; i++ )
				{
					LearnWord learnWord = new LearnWord();
					learnWord.Word = words[i];
					learnWord.Hide = false;
					mWords[i] = learnWord;
				}

				mLblCategory.Text = mVerse.Category;
				mLblTopic.Text = mVerse.Topic;
				mLblVerse.Text = mVerse.Passage;
				mTxtVerse.Text = mVerse.Text;
			}
		}

		/// <summary>
		/// Handle the Click event of the Hide button.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleBtnHideClick( object sender, EventArgs e )
		{
			_HideOrShow( true, int.Parse( mTxtNumberOfWords.Text ) );
		}

		/// <summary>
		/// Handle the MouseDown event of the Peek button.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleBtnPeekMouseDown( object sender, MouseEventArgs e )
		{
			mTxtVerse.Text = mVerse.Text;
		}

		/// <summary>
		/// Handle the MouseUp event of the Peek button.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleBtnPeekMouseUp( object sender, MouseEventArgs e )
		{
			_ShowLearnWords();
		}

		/// <summary>
		/// Handle the Click event of the Show button.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleBtnShowClick( object sender, EventArgs e )
		{
			_HideOrShow( false, int.Parse( mTxtNumberOfWords.Text ) );
		}

		/// <summary>
		/// Handle the CheckedChagned event of the Show First Letter checkbox.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleChkShowFirstLetterCheckedChanged( object sender, EventArgs e )
		{
			_ShowLearnWords();
		}

		/// <summary>
		/// Handle the KeyPress event of the Number Of Words textbox.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleTxtNumberOfWordsKeyPress( object sender, KeyPressEventArgs e )
		{
			// Only allow the user to enter numbers and to control the text.
			if( !(char.IsNumber( e.KeyChar ) || char.IsControl( e.KeyChar )) )
			{
				e.Handled = true;
			}
		}

		/// <summary>
		/// Handle the Event event of the Verse textbox.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _HandleTxtVerseEnter( object sender, EventArgs e )
		{
			// Do not let the textbox to gain focus.
			mLblVerse.Focus();
		}

		/// <summary>
		/// Hide or show words depending on the button pressed.
		/// </summary>
		/// <param name="hide"></param>
		/// <param name="number"></param>
		private void _HideOrShow( bool hide, int number )
		{
			// Get an index list of the words that we can either show or hide.
			List<int> availableIndices = new List<int>();
			for( int i = 0; i < mWords.Length; i++ )
			{
				// Add the index of the words that have the opposite value
				// of what we are trying to do.
				if( mWords[i].Hide != hide )
				{
					availableIndices.Add( i );
				}
			}

			// Show or hide all of the remaining indices if there aren't enough.
			if( availableIndices.Count <= number )
			{
				foreach( int index in availableIndices )
				{
					LearnWord learnWord = mWords[index];
					learnWord.Hide = hide;
					mWords[index] = learnWord;
				}
			}
			else
			{
				Random random = new Random();

				// Randomly hide or show from the available indices.
				for( int count = 0; count < number; count++ )
				{
					int randomIndex = random.Next( 0, availableIndices.Count - 1 );
					int index = availableIndices[randomIndex];

					LearnWord learnWord = mWords[index];
					learnWord.Hide = hide;
					mWords[index] = learnWord;

					availableIndices.RemoveAt( randomIndex );
				}
			}

			// Show the computed text
			_ShowLearnWords();
		}

		/// <summary>
		/// Show the learn words in the text area.
		/// </summary>
		private void _ShowLearnWords()
		{
			mTxtVerse.Text = string.Empty;
			foreach( LearnWord learnWord in mWords )
			{
				mTxtVerse.Text += learnWord.ToString( mChkShowFirstLetter.Checked ) + " ";
			}
			mTxtVerse.Text = mTxtVerse.Text.Trim();
		}

		#endregion Private Members

		#region Protected Members

		/// <summary>
		/// Handle the OnKeyDown event of the form.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnKeyDown( KeyEventArgs e )
		{
			if( e.KeyCode == Keys.Escape )
			{
				Close();
				e.Handled = true;
			}

			base.OnKeyDown( e );
		}

		#endregion Protected Members

		#region Other

		/// <summary>
		/// Structure used to determine which words are shown or hidden.
		/// </summary>
		private struct LearnWord
		{
			#region LearnWord Members

			public bool Hide;
			public string Word;

			public string ToString( bool showFirstLetter )
			{
				string displayWord;

				if( Hide )
				{
					displayWord = showFirstLetter
						? Word[0] + string.Empty.PadRight( Word.Length - 1, '_' )
						: string.Empty.PadRight( Word.Length, '_' );
				}
				else
				{
					displayWord = Word;
				}

				return displayWord;
			}

			#endregion LearnWord Members

		}

		#endregion Other

	}
}
